
#include "AUserData.h"
#include "AXML.h"
#include "AString.h"
#include "platform/CCFileUtils.h"

#include <libxml/parser.h>
#include <libxml/tree.h>

CAUserData* CAUserData::sm_pSharedUserData = null;

CAUserData::CAUserData()
{
	_bAutoSave = true;
	this->setListener(this);
	_load();
	sm_pSharedUserData = this;
}

CAUserData::~CAUserData(void)
{
	_save();
}

void CAUserData::onValueChanged(CAValueObject* pv)
{
	if (_bAutoSave)
	{
		_save();
	}
}

static bool _isFileExist(const char* pszFile)
{
	FILE *fp = fopen(pszFile, "r");
	bool bRet = false;

	if (fp)
	{
		bRet = true;
		fclose(fp);
	}

	return bRet;
}

#define USERDEFAULT_ROOT_NAME "settings"

static bool _createXMLFile(const char* pszFile)
{
	bool bRet = false;
	xmlDocPtr doc = NULL;

	do 
	{
		// new doc
		doc = xmlNewDoc(BAD_CAST"1.0");
		if (doc == NULL)
		{
			CCLOG("can not create xml doc");
			break;
		}

		// new root node
		xmlNodePtr rootNode = xmlNewNode(NULL, BAD_CAST USERDEFAULT_ROOT_NAME);
		if (rootNode == NULL)
		{
			CCLOG("can not create root node");
			break;
		}

		// set root node
		xmlDocSetRootElement(doc, rootNode);

		// save xml file
		xmlSaveFile(pszFile, doc);

		bRet = true;
	} while (0);

	// if doc is not null, free it
	if (doc)
	{
		xmlFreeDoc(doc);
	}

	return bRet;
}


#define XML_USER_DATA_FILE_NAME "ca_game_ud.xml"
void CAUserData::_load()
{
	GUARD_FUNCTION();
	
	CAString file = CCFileUtils::getWriteablePath() + XML_USER_DATA_FILE_NAME;
	if (!_isFileExist(file.c_str()))
	{
		_createXMLFile(file.c_str());
		return;
	}
	CAXML* pxml = CAXML::parse(file.c_str(), false);
	//load user data from pxml
	initialize(pxml->firstnode(USERDEFAULT_ROOT_NAME));
}

void CAUserData::_save()
{
	CAString file = CCFileUtils::getWriteablePath() + XML_USER_DATA_FILE_NAME;
	xmlDocPtr xmlDoc = NULL;
	xmlDoc = xmlReadFile(file.c_str(), "utf-8", XML_PARSE_RECOVER);
	//xmlNodePtr rootNode = xmlDocGetRootElement(xmlDoc);
	// new root node
	xmlNodePtr rootNode = xmlNewNode(NULL, BAD_CAST USERDEFAULT_ROOT_NAME);
	// set root node
	xmlDocSetRootElement(xmlDoc, rootNode);

	//std::vector<CAString> keys = this->allKeys();
	CCArray* keys = this->allKeys();
	for (size_t n = 0; n < keys->count(); n++)
	{
		const char* key = ((CCString*)keys->objectAtIndex(n))->getCString();
		xmlNodePtr tmpNode = xmlNewNode(NULL, BAD_CAST "key");
		CAValueObject* pvalue = this->getValue(key);
		char sz[128];
		CAString val;
		CAString type;
		switch (pvalue->getType())
		{
		case SVT_Float:
			sprintf(sz, "%f", pvalue->getFloat());
			type = "float";
			val = sz;
			break;
		case SVT_String:
			val = pvalue->getString();
			type = "CAString";
			break;
		case SVT_Point:
			sprintf(sz, "%f,%f", pvalue->getPoint().x, pvalue->getPoint().y);
			type = "point";
			val = sz;
			break;
		case SVT_Size:
			sprintf(sz, "%f,%f", pvalue->getSize().width, pvalue->getSize().height);
			type = "size";
			val = sz;
			break;
		case SVT_Rect:
			sprintf(sz, "%f,%f,%f,%f", pvalue->getRect().origin.x, pvalue->getRect().origin.y, pvalue->getRect().size.width, pvalue->getRect().size.height);
			type = "rect";
			val = sz;
			break;
		case SVT_Bool:
			sprintf(sz, "%s", pvalue->getBool() ? "true" : "false");
			type = "bool";
			val = sz;
			break;
		case SVT_Integer:
			sprintf(sz, "%d", pvalue->getInteger());
			type = "int";
			val = sz;
			break;
		}
		xmlAttrPtr attrName = xmlNewProp(tmpNode, BAD_CAST "name", BAD_CAST key);
		xmlAttrPtr attrValue = xmlNewProp(tmpNode, BAD_CAST type.c_str(), BAD_CAST val.c_str());
		xmlAddChild(rootNode, tmpNode);
	}
	xmlSaveFile(file.c_str(), xmlDoc);
	xmlFreeDoc(xmlDoc);
	xmlDoc = NULL;
}
